#include "entity_manager.h"

#include <boost/foreach.hpp>

namespace space {
	namespace managers {

		entity_ptr entity_manager::create(void) {
			entity_ptr ptr = make_shared<entity>();

			_entities.add(ptr);

			return ptr;
		}
		entity_ptr entity_manager::create(const std::string &name) {
			entity_ptr ptr = make_shared<entity>(name);

			_entities.add(ptr);

			return ptr;
		}

		result entity_manager::destroy(entity_ptr ptr) {
			
			// invalidate the entity
			ptr->set_valid(false);

			// search all tags and remove it!
			concurrency::concurrent_unordered_map<std::string, std::list<entity_ptr>>::iterator tags_iter;
			for(tags_iter = _tags.begin(); tags_iter != _tags.end(); tags_iter++) {
				tags_iter->second.remove(ptr);
			}
			// delete it from the entities active collection
			return _entities.remove(ptr);
		}

		result entity_manager::assign_tag(const std::string &tag, entity_ptr ptr) {
			std::list<entity_ptr>::const_iterator list_iter;
			concurrency::concurrent_unordered_map<std::string, std::list<entity_ptr>>::const_iterator tags_iter;

			// make sure the entity doesnt already exist in the tag.
			tags_iter = _tags.find(tag);
			if(_tags.find(tag) != _tags.end()) {
				list_iter = tags_iter->second.begin();
				for(list_iter; list_iter != tags_iter->second.end(); list_iter++) {
					if(*list_iter == ptr)
						return RESULT_ALREADY_EXISTS;
				}
			} else {
				_tags[tag] = std::list<entity_ptr>();
			}
			
			_tags[tag].push_back(ptr);
			
			return RESULT_OK;
		}
		result entity_manager::remove_tag(const std::string &tag, entity_ptr ptr) {
			std::list<entity_ptr>::iterator list_iter;
			concurrency::concurrent_unordered_map<std::string, std::list<entity_ptr>>::const_iterator tags_iter;

			// make sure the entity doesnt already exist in the tag.
			tags_iter = _tags.find(tag);
			if(_tags.find(tag) != _tags.end()) {
				_tags[tag].remove(ptr);
			} 
			

			return RESULT_NOT_FOUND;
		}

		result entity_manager::tags(std::vector<std::string> & tagNames) const {
			concurrency::concurrent_unordered_map<std::string, std::list<entity_ptr>>::const_iterator tags_iter;

			tagNames.clear();
			for(tags_iter = _tags.begin(); tags_iter != _tags.end(); tags_iter++) {
				tagNames.push_back(tags_iter->first);
			}

			return RESULT_OK;
		}

		result entity_manager::find_by_tag(const std::string &tag, std::vector<entity_ptr> &ret_vector) const {
			concurrency::concurrent_unordered_map<std::string, std::list<entity_ptr>>::const_iterator tags_iter;
			std::list<entity_ptr>::const_iterator list_iter;
		
			ret_vector.clear();

			tags_iter = _tags.find(tag);
			if(_tags.find(tag) != _tags.end()) {
				list_iter = tags_iter->second.begin();
				for(list_iter; list_iter != tags_iter->second.end(); list_iter++) {
					ret_vector.push_back(*list_iter);
				}
			} else {
				return RESULT_NOT_FOUND;
			}

			return RESULT_OK;
		}
		entity_ptr entity_manager::find_by_name(const std::string name) const {
			return _entities.find_by_name(name);
		}
		entity_ptr entity_manager::find_by_id(const u_int64 id) const {
			return _entities.find_by_id(id);
		}

		result entity_manager::on_post_update(i_engine_ptr engine, float delta) {
			_entities.on_post_update(engine, delta);

			return RESULT_OK;
		}
		result entity_manager::on_pre_update(i_engine_ptr engine, float delta) {
			_entities.on_pre_update(engine, delta);

			return RESULT_OK;
		}
		result entity_manager::on_update(i_engine_ptr engine, float delta) {
			_entities.on_update(engine, delta);

			return RESULT_OK;
		}

		result entity_manager::initialize(i_engine_ptr engine) {

			return RESULT_NOT_IMPL;
		}
		result entity_manager::release(i_engine_ptr engine) {

			return RESULT_NOT_IMPL;
		}

		entity_manager::entity_manager() {

		}
		entity_manager::~entity_manager() {


		}
	};
};